﻿using AutoRevit.Ribbon.Ribbon.Mapper;
using RibbonItem = Autodesk.Revit.UI.RibbonItem;
using RibbonPanel = Autodesk.Revit.UI.RibbonPanel;

namespace AutoRevit.Ribbon;

/// <summary>
/// 控件管理器
/// </summary>
public partial class ControlManager
{
    private readonly IReadOnlyDictionary<Type, Action<RibbonPanel, RibbonItem?, ControlItemMapper>> mapMethods;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="uiControlApp"></param>
    public ControlManager(UIControlledApplication uiControlApp) : this()
    {
        UiControlApp = uiControlApp;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="uiApp"></param>
    public ControlManager(UIApplication uiApp) : this()
    {
        UiApp = uiApp;
    }

    private ControlManager()
    {
        mapMethods = new Dictionary<Type, Action<RibbonPanel, RibbonItem?, ControlItemMapper>>()
        {
            { typeof(PushButtonMapper), PushButtonMap },
            { typeof(SplitButtonMapper), SplitButtonMap }
        };
    }

    /// <summary>
    /// 
    /// </summary>
    public UIControlledApplication? UiControlApp { get; }

    /// <summary>
    /// 
    /// </summary>
    public UIApplication? UiApp { get; }
}

public partial class ControlManager
{
    /// <summary>
    /// 映射
    /// </summary>
    /// <param name="tabMappers"></param>
    public void Map(IEnumerable<TabMapper> tabMappers)
    {
        foreach (var tabMapper in tabMappers)
        {
            var tab = GetRibbonTab(tabMapper.Name);
            tabMapper.Control = tab;

            Map(tabMapper.Panels, tab);

            tab.IsVisible = tabMapper.Visible;
            tab.IsEnabled = tabMapper.Enabled;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="panelMappers"></param>
    /// <param name="tab"></param>
    public void Map(IEnumerable<PanelMapper> panelMappers, RibbonTab? tab = null)
    {
        foreach (var panelMapper in panelMappers)
        {
            RibbonPanel panel;

            if (tab is null)
            {
                panel = GetRibbonPanel(panelMapper.Name);
            }
            else
            {
                panel = GetRibbonPanel(tab, panelMapper.Name);
            }

            panelMapper.Control = panel;

            foreach (var item in panelMapper.Items)
            {
                var ribbonItem = panel.GetItems().FirstOrDefault(t => t.Name == item.Name);

                var type = item.GetType();

                if (mapMethods.TryGetValue(type, out var action))
                {
                    action(panel, ribbonItem, item);
                }
                else
                {
                    var method = mapMethods.FirstOrDefault(t => type.IsSubclassOf(t.Key) || type.GetInterfaces().Any(iface => iface == t.Key)).Value;
                    method?.Invoke(panel, ribbonItem, item);
                }
            }

            panel.Visible = panelMapper.Visible;
            panel.Enabled = panelMapper.Enabled;
        }
    }

    /// <summary>
    /// 获取Tab
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public RibbonTab GetRibbonTab(string name)
    {
        var tab = ComponentManager.Ribbon.Tabs.FirstOrDefault(t => t.Title == name);

        if (tab is null)
        {
            if (UiControlApp is not null)
            {
                UiControlApp!.CreateRibbonTab(name);
            }
            else
            {
                UiApp!.CreateRibbonTab(name);
            }
        }

        return ComponentManager.Ribbon.Tabs.FirstOrDefault(t => t.Title == name)!;
    }

    /// <summary>
    /// 获取Panel
    /// </summary>
    /// <param name="ribbonTab"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    public RibbonPanel GetRibbonPanel(RibbonTab ribbonTab, string name)
    {
        List<RibbonPanel> panels;

        if (UiControlApp is not null)
        {
            panels = UiControlApp!.GetRibbonPanels(ribbonTab.Name);
        }
        else
        {
            panels = UiApp!.GetRibbonPanels(ribbonTab.Name);
        }
        var panel = panels.FirstOrDefault(t => t.Name == name);

        if (panel is null)
        {
            if (UiControlApp is not null)
            {
                panel = UiControlApp!.CreateRibbonPanel(ribbonTab.Name, name);
            }
            else
            {
                panel = UiApp!.CreateRibbonPanel(ribbonTab.Name, name);
            }
        }

        return panel;
    }

    /// <summary>
    /// 获取Panel
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public RibbonPanel GetRibbonPanel(string name)
    {
        List<RibbonPanel> panels;

        if (UiControlApp is not null)
        {
            panels = UiControlApp!.GetRibbonPanels();
        }
        else
        {
            panels = UiApp!.GetRibbonPanels();
        }

        var panel = panels.FirstOrDefault(t => t.Name == name);

        if (panel is null)
        {
            if (UiControlApp is not null)
            {
                panel = UiControlApp!.CreateRibbonPanel(name);
            }
            else
            {
                panel = UiApp!.CreateRibbonPanel(name);
            }
        }

        return panel;
    }

    private void PushButtonMap(RibbonPanel panel, RibbonItem? ribbonItem, ControlItemMapper mapper)
    {
        if (mapper is PushButtonMapper practicalMapper)
        {
            if (ribbonItem is null)
            {
                ribbonItem = panel.AddItem(practicalMapper.GetData());
            }

            practicalMapper.Control = ribbonItem as PushButton;

            ribbonItem!.Visible = mapper.Visible;
            ribbonItem!.Enabled = mapper.Enabled;
        }
    }

    private void SplitButtonMap(RibbonPanel panel, RibbonItem? ribbonItem, ControlItemMapper mapper)
    {
        if (mapper is SplitButtonMapper practicalMapper)
        {
            if (ribbonItem is null)
            {
                ribbonItem = panel.AddItem(practicalMapper.GetData());
            }

            practicalMapper.Control = ribbonItem as SplitButton;

            var splitButton = ribbonItem as SplitButton;

            splitButton!.IsSynchronizedWithCurrentItem = practicalMapper.IsSynchronizedWithCurrentItem;

            List<PushButton> pushButtons = [];

            foreach (var item in practicalMapper.Items)
            {
                var pushButton = splitButton!.GetItems().FirstOrDefault(t => t.Name == item.Name);

                if (pushButton is null)
                {
                    pushButton = splitButton.AddPushButton(item.GetData());
                    item.Control = pushButton;
                }

                pushButton.Visible = item.Visible;
                pushButton.Enabled = item.Enabled;

                pushButtons.Add(pushButton);
            }

            splitButton!.CurrentButton = pushButtons.FirstOrDefault(t => t.Name == practicalMapper.CurrentButtonName);
            splitButton!.Visible = mapper.Visible;
            splitButton!.Enabled = mapper.Enabled;
        }
    }
}
